/**
 * elColorPicker. JQuery plugin
 * Create drop-down colors palette.
 *
 * Usage:
 * $(selector).elColorPicker(opts)
 *
 * set color after init:
 * var c = $(selector).elColorPicker(opts)
 * c.val('#ffff99)
 *
 * Get selected color:
 * var color = c.val();
 *
 * Notice!
 *   Palette created only after first click on element (lazzy loading)
 *
 * Options:
 *   colors - colors array (by default display 256 web safe colors)
 *   color  - current (selected) color
 *   class - css class for display "button" (element on wich plugin was called)
 *   paletteClass - css class for colors palette
 *   palettePosition - string indicate where palette will created:
 *      'inner' - palette will attach to element (acceptable in most cases)
 *      'outer' - palette will attach to document.body.
 *                Use, when create color picker inside element with overflow == 'hidden', for example in ui.dialog
 *   update - function wich update button view on select color (by default set selected color as background)
 *   change - callback, called when color was selected (by default write color to console.log)
 *   name   - hidden text field in wich selected color value will saved
 *
 * @author:    Dmitry Levashov (dio) dio@std42.ru
 *
 **/

;(function($){

  $.widget("el.colorPicker", {
    options: {
      "class"          : "el-colorpicker",
      "paletteClass"   : "el-palette",
      "palettePosition": "inner",
      "name"           : "color",
      "color"          : "",
      "update"         : null,
      "change"         : null,
      "colors"         : [
        "#ffffff", "#cccccc", "#999999", "#666666", "#333333", "#000000",
        "#ffcccc", "#cc9999", "#996666", "#663333", "#330000",
        "#ff9999", "#cc6666", "#cc3333", "#993333", "#660000",
        "#ff6666", "#ff3333", "#ff0000", "#cc0000", "#990000",
        "#ff9966", "#ff6633", "#ff3300", "#cc3300", "#993300",
        "#ffcc99", "#cc9966", "#cc6633", "#996633", "#663300",
        "#ff9933", "#ff6600", "#ff9900", "#cc6600", "#cc9933",
        "#ffcc66", "#ffcc33", "#ffcc00", "#cc9900", "#996600",
        "#ffffcc", "#cccc99", "#999966", "#666633", "#333300",
        "#ffff99", "#cccc66", "#cccc33", "#999933", "#666600",
        "#ffff66", "#ffff33", "#ffff00", "#cccc00", "#999900",
        "#ccff66", "#ccff33", "#ccff00", "#99cc00", "#669900",
        "#ccff99", "#99cc66", "#99cc33", "#669933", "#336600",
        "#99ff33", "#99ff00", "#66ff00", "#66cc00", "#66cc33",
        "#99ff66", "#66ff33", "#33ff00", "#33cc00", "#339900",
        "#ccffcc", "#99cc99", "#669966", "#336633", "#003300",
        "#99ff99", "#66cc66", "#33cc33", "#339933", "#006600",
        "#66ff66", "#33ff33", "#00ff00", "#00cc00", "#009900",
        "#66ff99", "#33ff66", "#00ff33", "#00cc33", "#009933",
        "#99ffcc", "#66cc99", "#33cc66", "#339966", "#006633",
        "#33ff99", "#00ff66", "#00ff99", "#00cc66", "#33cc99",
        "#66ffcc", "#33ffcc", "#00ffcc", "#00cc99", "#009966",
        "#ccffff", "#99cccc", "#669999", "#336666", "#003333",
        "#99ffff", "#66cccc", "#33cccc", "#339999", "#006666",
        "#66cccc", "#33ffff", "#00ffff", "#00cccc", "#009999",
        "#66ccff", "#33ccff", "#00ccff", "#0099cc", "#006699",
        "#99ccff", "#6699cc", "#3399cc", "#336699", "#003366",
        "#3399ff", "#0099ff", "#0066ff", "#066ccc", "#3366cc",
        "#6699ff", "#3366ff", "#0033ff", "#0033cc", "#003399",
        "#ccccff", "#9999cc", "#666699", "#333366", "#000033",
        "#9999ff", "#6666cc", "#3333cc", "#333399", "#000066",
        "#6666ff", "#3333ff", "#0000ff", "#0000cc", "#009999",
        "#9966ff", "#6633ff", "#3300ff", "#3300cc", "#330099",
        "#cc99ff", "#9966cc", "#6633cc", "#663399", "#330066",
        "#9933ff", "#6600ff", "#9900ff", "#6600cc", "#9933cc",
        "#cc66ff", "#cc33ff", "#cc00ff", "#9900cc", "#660099",
        "#ffccff", "#cc99cc", "#996699", "#663366", "#330033",
        "#ff99ff", "#cc66cc", "#cc33cc", "#993399", "#660066",
        "#ff66ff", "#ff33ff", "#ff00ff", "#cc00cc", "#990099",
        "#ff66cc", "#ff33cc", "#ff00cc", "#cc0099", "#990066",
        "#ff99cc", "#cc6699", "#cc3399", "#993366", "#660033",
        "#ff3399", "#ff0099", "#ff0066", "#cc0066", "#cc3366",
        "#ff6699", "#ff3366", "#ff0033", "#cc0033", "#990033"
      ]
    },
    _create     : function()
                  {
                    var self = $.extend(this, {
                      _inited: false,
                      hidden : $("<input />", {type: "hidden", name: this.options.name, value: this.options.color}),
                      palette: $("<div />", {"class": [this.options.paletteClass, "rounded-3"].join(" "), "style": "display:none;"}),
                      preview: $("<div />", {"class": "preview rounded-3"}).click(function(e){e.stopPropagation();self._setColor(self.input.val());}),
                      input  : $("<input />", {"type": "text", "class": "rounded-3", "size": 8}).
                                 click(function(e){e.stopPropagation();this.focus();}).
                                 keydown(function(e)
                                 {
                                   if (e.ctrlKey || e.metaKey)
                                      return true;
                                 // on esc - close palette
                                   if (e.keyCode == $.ui.keyCode.ESCAPE)
                                     return self.mouseleave();
                                 // allow input only hex color value
                                   if (($.inArray(e.keyCode, [$.ui.keyCode.BACKSPACE, $.ui.keyCode.ENTER, $.ui.keyCode.LEFT, $.ui.keyCode.RIGHT, $.ui.keyCode.DELETE]) < 0) &&
                                       ((e.keyCode < 48) || (57 < e.keyCode)) && ((e.keyCode < 65) || (70 < e.keyCode)))
                                     return false;
                                   var c = this.value;
                                   if ((c.length == 7) || (c.length == 0))
                                   {
                                      if (e.keyCode == $.ui.keyCode.ENTER)
                                      {
                                        e.stopPropagation();
                                        e.preventDefault();
                                        self._setColor(c);
                                        self.palette.slideUp();
                                      }
                                      if ($.inArray(e.keyCode, [$.ui.keyCode.BACKSPACE, $.ui.keyCode.LEFT, $.ui.keyCode.RIGHT, $.ui.keyCode.DELETE]) < 0)
                                        return false;
                                   }
                                 }).
                                 keyup(function(){var c=this.value;if((c.length==7)&&/^#[0-9abcdef]{6}$/i.test(c))self.val(c);})
                    });
                    this.element.
                      empty().
                      addClass([this.options["class"], "rounded-3"].join(" ")).
                      css({"position": "relative", "background-color": this.options.color}).
                      append(this.hidden).
                      click(function()
                      {
                        if (!self._inited)
                        {
                          self._reset();
                          self._inited = true;
                        }
                        var $this = $(this);
                        if (!$this.hasClass("disabled"))
                        {
                          if ((self.options.palettePosition == "outer") && self.palette.is(":hidden"))
                          {
                            var o = $this.offset();
                            var w = self.palette.width();
                            self.palette.css({
                              left: [w <= $this.parents("body").width() - o.left ? o.left : o.left + $this.outerWidth() - w, "px"].join(""),
                              top : [o.top + $this.height() + 1, "px"].join("")
                            });
                          }
                          self.palette.slideToggle();
                        }
                      });
                    for (var i = 0; i < this.options.colors.length; ++i)
                      $("<div />", {
                        "class"       : "color",
                        "style"       : ["background-color:", ";"].join(this.options.colors[i]),
                        "title"       : this.options.colors[i],
                        "unselectable": "on"
                      }).appendTo(this.palette);
                    this.palette.children("div").
                      mouseenter(function(){self.input.val(this.title);self.preview.css("background-color",this.title);}).
                      click(function(e){e.stopPropagation();self._setColor(this.title);});
                    this.input.add(this.preview).appendTo($("<div />", {"class": "panel"}).appendTo(this.palette.append("<div class='clearfix' />")));
                    if (this.options.palettePosition == "outer")
                    {
                      this.palette.appendTo(this.element.parents("body:first")).mouseleave(function(){self._hidePalette();});
                      this.mouseleave(function(e){if(e.relatedTarget!=self.palette[0]){self._hidePalette();}});
                    }
                    else
                      this.element.append(this.palette).mouseleave(function(){self._hidePalette();});
                  },
    val         : function(v)
                  {
                    if (v == null)
                      return this.hidden.val();
                    this.hidden.val(v);
                    if ($.isFunction(this.options.update))
                      this.options.update(v);
                    else
                      this.css("background-color", v);
                    this.preview.css("background-color", v);
                    this.input.val(v);
                    return this.element;
                  },
    _setColor   : function(c)
                  {
                    this.val(c);
                    if ($.isFunction(this.options.change))
                      this.options.change(this.val());
                    this.palette.slideUp();
                  },
    _reset      : function(){this.val(this.val());},
    _hidePalette: function(){this.palette.slideUp();this._reset();}
  });

})(jQuery);
